package lg.minecraft.plugin.pokedex.storage;

import com.cobblemon.mod.common.pokemon.Species;
import lg.minecraft.plugin.pokedex.Generations;
import lg.minecraft.plugin.pokedex.LGPokedex;
import lg.minecraft.plugin.pokedex.util.LRUCacheMap;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * @author langle__
 * @version 1.0
 */
public class YMALStorage extends DataStorage {

    private final Map<UUID, Entry> dataMap;
    private final File dataFolder;

    public YMALStorage(File dataFolder, int maxStorageCount) {
        this.dataFolder = dataFolder;
        this.dataMap = new LRUCacheMap<>(maxStorageCount);
        if (!dataFolder.exists()) {
            if (!dataFolder.mkdirs()) {
                LGPokedex.getInstance().getLogger().warning("Failed to create data folder.");
            }
        }
    }

    public Entry getEntry(UUID uuid) {
        Entry entry = dataMap.get(uuid);
        if (entry == null) {
            File file = new File(dataFolder, uuid.toString() + ".yml");
            YamlConfiguration data = YamlConfiguration.loadConfiguration(file);
            entry = new Entry(file, data);
            dataMap.put(uuid, entry);
        }
        return entry;
    }

    public void removeEntry(UUID uuid) {
        dataMap.remove(uuid);
    }

    public void saveData(UUID uuid) {
        getEntry(uuid).save();
    }

    public void asyncSaveData(UUID uuid) {
        Bukkit.getScheduler().runTaskAsynchronously(LGPokedex.getInstance(), () -> saveData(uuid));
    }

    public void saveAllData() {
        dataMap.values().forEach(Entry::save);
    }

    public void asyncSaveAllData() {
        Bukkit.getScheduler().runTaskAsynchronously(LGPokedex.getInstance(), this::saveAllData);
    }

    @Override
    public void setGenerationRewardClaimed(@NotNull UUID uuid, @NotNull Generations gen, boolean claimed) {
        Entry entry = getEntry(uuid);
        entry.data.set(gen.name, claimed);
    }

    @Override
    public boolean isGenerationRewardClaimed(@NotNull UUID uuid, @NotNull Generations gen) {
        Entry entry = getEntry(uuid);
        return entry.data.getBoolean(gen.name);
    }

    @Override
    public void markSpeciesAsReceived(@NotNull UUID uuid, @NotNull Species species) {
        Entry entry = getEntry(uuid);
        List<String> list = entry.data.getStringList("receivedSpecies");
        String resource = species.resourceIdentifier.toString();
        if (!list.contains(resource)) {
            list.add(resource);
            entry.data.set("receivedSpecies", list);
        }
    }

    @Override
    public void unmarkSpeciesAsReceived(@NotNull UUID uuid, @NotNull Species species) {
        Entry entry = getEntry(uuid);
        List<String> list = entry.data.getStringList("receivedSpecies");
        String resource = species.resourceIdentifier.toString();
        if (list.contains(resource)) {
            list.remove(resource);
            entry.data.set("receivedSpecies", list);
        }
    }

    @Override
    public boolean hasSpeciesBeenReceived(@NotNull UUID uuid, @NotNull Species species) {
        Entry entry = getEntry(uuid);
        return entry.data.getStringList("receivedSpecies").contains(species.resourceIdentifier.toString());
    }

    @Override
    public List<String> getClaimedRewardSpecies(@NotNull UUID uuid) {
        Entry entry = getEntry(uuid);
        return entry.data.getStringList("receivedSpecies");
    }

    public record Entry(File file, YamlConfiguration data) {

        public void save() {
            try {
                data.save(file);
            } catch (IOException e) {
                LGPokedex.getInstance().getLogger().warning("Failed to save player data for " + file.getName());
            }
        }

    }

}
